package NICE_CORE

import chisel3._
import chisel3.util._

class e203_nice_core_144k extends Module with RequireAsyncReset
    with Nice_Core_Config with SystemConfig with  CIM_Config with Mvm_config_2 {
  val io = IO(new Bundle(){
    val system = new SystemIO()
    val req = Flipped(DecoupledIO(new CmdReqIO()))
    val rsp = DecoupledIO(new CmdRspIO)
    val memreq = DecoupledIO(new MemReqIO())
    val memrsp = Flipped(DecoupledIO(new MemRspIO()))
    val k144 = new K144IO()
  })
  //********* 1.FSM   ******************
  val idle:: push :: save::mvm ::config::Nil = Enum(5)
  val state = RegInit(idle)
  val isidle = state === idle
  val ispush = state === push
  val ismvm  = state === mvm
  val issave = state === save
  val isconfig = state === config
  //***********1.1 decode***********
  val opcode     = Mux(io.req.valid,io.req.bits.inst(6,0),0.U)
  val rv32_func3 = Mux(io.req.valid,io.req.bits.inst(14,12),0.U)
  val rv32_func7 = Mux(io.req.valid,io.req.bits.inst(31,25),0.U)
  val opcode_custom3 = opcode === "b1111011".U
  val rv32_func3_000 = rv32_func3 === "b000".U
  val rv32_func3_010 = rv32_func3 === "b010".U
  val rv32_func3_011 = rv32_func3 === "b011".U
  val rv32_func7_0000001 = rv32_func7 === "b0000001".U
  val rv32_func7_0010001 = rv32_func7 === "b0010001".U
  val rv32_func7_0010010 = rv32_func7 === "b0010010".U
  val rv32_func7_0000010 = rv32_func7 === "b0000010".U
  val custom3_push = opcode_custom3 & rv32_func3_011 & rv32_func7_0010001 & isidle
  val custom3_save = opcode_custom3 & rv32_func3_011 & rv32_func7_0010010 & isidle
  val custom3_mvm  = opcode_custom3 & rv32_func3_011 & rv32_func7_0000001 & isidle
  val custom3_config= opcode_custom3& rv32_func3_011 & rv32_func7_0000010 & isidle
  //*********** 1.2 state shift***********
  val push_done = Wire(Bool());val save_done = Wire(Bool());val mvm_done = Wire(Bool());
  switch(state){
    is(idle){ state := Mux(custom3_push,push,
                       Mux(custom3_save,save,
                       Mux(custom3_mvm,mvm,
                       Mux(custom3_config,config,idle))))}
    is(push){ state := Mux(push_done,idle,push)}
    is(save){ state := Mux(save_done,idle,save)}
    is(mvm){  state  := Mux(mvm_done,idle,mvm)}
  }
  val config_done = isconfig
  io.rsp.valid      := push_done | mvm_done| save_done |config_done
  io.system.holdup  := ispush | issave
  io.system.active  := Mux(isidle,io.req.valid,true.B)
  io.req.ready      := isidle
  io.rsp.bits.err := io.memrsp.bits.err & io.memrsp.valid & io.memrsp.ready
  io.rsp.bits.rdat:= 0.U
  io.memreq.bits.size := "b10".U
  io.memreq.bits.read := ~(issave|(isidle & custom3_save))
  io.memrsp.ready     := true.B
  val is2mem = ispush|issave
  val custom_mem = custom3_push | custom3_save
  io.memreq.valid     := custom3_push|custom3_save|is2mem
  //*********2. Datapath ******************
  val con_para = Wire(new config_para)
  con_para.adc_range  := RegEnable(io.req.bits.rs1(7, 0),0.U,custom3_config)
  con_para.out_shift  := RegEnable(io.req.bits.rs1(15,8),0.U,custom3_config)


  //******2.1 mem addr generate
  val maddr_acc_r = RegInit(0.U(E203_ADDR_SIZE.W))
  val memreq_hsked = io.memreq.valid & io.memreq.ready
  val maddr_acc_ena = (is2mem & memreq_hsked)|(isidle & custom_mem)
  io.memreq.bits.addr := Mux(custom3_save|custom3_push,io.req.bits.rs1, maddr_acc_r)
  maddr_acc_r := Mux(maddr_acc_ena,io.memreq.bits.addr + 4.U,maddr_acc_r)
  //*****2.2 mem access time generate
  val transize = RegInit(0.U(8.W))
  val push_num = io.req.bits.rs2(10,0) - 1.U
  when(custom3_push){
    transize := push_num(10,4) + io.req.bits.rs2(21,15)
  }.elsewhen(custom3_save){
    transize := push_num(10,2) + io.req.bits.rs2(21,13)
  }
  // *****2.3 push index reg generate
  val push_cnt_r = RegInit(0.U(7.W))
  push_cnt_r := Mux(push_done,0.U,Mux(custom3_push,io.req.bits.rs2(21,15),
                Mux(ispush&memreq_hsked,push_cnt_r+1.U,push_cnt_r)))
  push_done := ispush &  (push_cnt_r === transize)
  //*******2.4 push buffer generate
  val memrsp_hsked = io.memrsp.ready & io.memrsp.valid
  val push_buf_r  = RegInit(VecInit(Seq.fill(PUSH_MAX_SIZE)(0.U(E203_XLEN.W))))
  val push_buf_we = VecInit(Seq.fill(PUSH_MAX_SIZE)(false.B))
  for (i<-0 until PUSH_MAX_SIZE){
    push_buf_we(i) := memrsp_hsked & ispush &(push_cnt_r === i.U)
    push_buf_r(i) := Mux(push_buf_we(i),io.memrsp.bits.rdata,push_buf_r(i))
  }
  val push_buf = push_buf_r.asUInt()
  //********2.5 save buffer index reg generate
  val save_cnt_r   = RegInit(0.U(7.W))
  val save_cmd_cnt = Mux(custom3_save,io.req.bits.rs2(18,12),Mux(issave,save_cnt_r,0.U))
  save_done := (save_cmd_cnt === transize) & issave
  val save_cnt_ena = custom3_save|(memrsp_hsked & issave & ~save_done)
  save_cnt_r := Mux(save_cnt_ena,save_cmd_cnt+1.U,save_cnt_r)

  //**********3.mvm done
  //val mem_start = RegEnable(true.B,false.B,custom3_mvm)
  val mvm_start = RegInit(false.B)
  mvm_start := Mux(custom3_mvm,true.B,false.B)
  val rcbd = Wire(new mvm_IO_2())
  rcbd.row_begin := RegEnable(io.req.bits.rs2(21,11),0.U,custom3_mvm)
  rcbd.row_end   := RegEnable(io.req.bits.rs1(31,16),0.U,custom3_mvm)
  rcbd.col_begin := RegEnable(io.req.bits.rs2(10,0),0.U,custom3_mvm)
  rcbd.col_end   := RegEnable(io.req.bits.rs1(15,0),0.U,custom3_mvm)
//  val cim_out   = cim_mvm_2(mem_start,rcbd,push_buf)
//  val save_buf_wire = cim_out._2.asTypeOf(Vec(COL_NUM/2,UInt(E203_XLEN.W)))
  //************************end 144k feedback
  //************3.1 acc cim_result to mvm_result
  val cim_done_pos = RegNext(io.k144.i_result_done)
  val cim_done_neg = RegNext(cim_done_pos)
  val cim_done = cim_done_pos & (~cim_done_neg)

  val cim_result = io.k144.i_result_buf.asTypeOf(Vec(COL_NUM,UInt(4.W)))
  val cim_result_real = VecInit(Seq.fill(COL_NUM)(0.S(4.W)))
  val mvm_result = VecInit(Seq.fill(COL_NUM)(0.S(8.W)))
  for(i<-0 until COL_NUM){
    cim_result_real(i) := (cim_result(i) ^ "b1000".U).asSInt()
//    when(custom3_mvm){
//      mvm_tmp(i) := 0.S
//    }.elsewhen(cim_done){
//      mvm_tmp(i) := mvm_tmp(i) + cim_result_real(i)
//    }
//    mvm_tmp_shift(i) := mvm_tmp(i) >> con_para.out_shift
    mvm_result(i):= cim_result_real(i)
  }
  val save_buf_wire = mvm_result.asTypeOf(Vec(COL_NUM/4,UInt(E203_XLEN.W)))
  io.memreq.bits.wdata := save_buf_wire(save_cmd_cnt)
  mvm_done := ismvm &  cim_done

  io.k144.o_push_buf  := push_buf
  io.k144.o_push_done := push_done
  io.k144.o_start     := mvm_start
  io.k144.o_save_done := RegNext(save_done)
  io.k144.o_row_index := rcbd.row_begin
  io.k144.o_col_index := rcbd.col_begin
  io.k144.o_row_length:= rcbd.row_end
  io.k144.o_col_length:= rcbd.col_end
}


